/**
 * @Author: Jiang Zhongxun
 * @Date: 2025-01-13 10:57:48
 * @FilePath: \ESP32_Smart_Lock\main\drivers\FINGERPRINT_Driver.c
 * @Description: HLK-FPM383C 指纹模块
 * @Copyright (c) 2025 by JiangZhongxun, All Rights Reserved.
 */
#include "FINGERPRINT_Driver.h"

/**
 * @description: 初始化指纹模块
 * @param {*} 无参
 * @return {*} 无返回值
 */
void FINGERPRINT_Init(void)
{
    // 配置 UART 驱动程序的参数、通信引脚并安装驱动程序
    uart_config_t uart_config = {
        .baud_rate = 57600,                    // 波特率
        .data_bits = UART_DATA_8_BITS,         // 8个数据位
        .parity = UART_PARITY_DISABLE,         // 禁用奇偶校验
        .stop_bits = UART_STOP_BITS_1,         // 1个停止位
        .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, // 硬件流控制模式：禁用硬件流控制
        .source_clk = UART_SCLK_DEFAULT        // 选择 UART 时钟源
    };
    int intr_alloc_flags = 0;
    // 将串口 1 的输入和输出引脚设置为 P20 和 P21
    uart_driver_install(
        UART_NUM_1,      // UART端口号，最大端口号为（UART_NUM_MAX - 1）
        BUF_SIZE * 2,    // UART RX环缓冲区大小
        0,               // UART TX环缓冲区大小。如果设置为零，驱动程序将不使用TX缓冲区，TX函数将阻塞任务，直到所有数据都发送出去
        0,               // UART事件队列大小 / 深度
        NULL,            // UART事件队列句柄（out参数）如果成功，将在这里编写一个新的队列句柄，以提供对UART事件的访问。如果设置为NULL，驱动程序将不使用事件队列。
        intr_alloc_flags // 用于分配中断的标志。一个或多个（ORred）ESP_INTR_FLAG_ *值。
    );
    // 配置串口 1
    uart_param_config(UART_NUM_1, &uart_config);
    // 为串口 1 分配 TX 和 RX 引脚
    uart_set_pin(UART_NUM_1, UART_TX_PIN, UART_RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
    // 中断
    gpio_config_t io_conf = {};                        // 初始化 GPIO 引脚
    io_conf.intr_type = GPIO_INTR_POSEDGE;             // 中断触发为上升沿触发
    io_conf.mode = GPIO_MODE_INPUT;                    // 设置为输入模式
    io_conf.pin_bit_mask = (1ULL << FINGER_TOUCH_INT); // 选择 GPIO 引脚
    io_conf.pull_up_en = 1;                            // 使能上拉
    gpio_config(&io_conf);                             // 使配置生效

    printf("指纹模块初始化: 成功......\r\n");
}

/**
 * @description: 获取指纹芯片的序列号
 *               见技术手册: 3.4.3 获取芯片唯一序列号PS_GetChipSN
 * @param {*} 无参
 * @return {*} 无返回值
 */
void FINGERPRINT_GetSerialNumber(void)
{
    vTaskDelay(200 / portTICK_PERIOD_MS);
    uint8_t *data = (uint8_t *)malloc(BUF_SIZE);
    // 获取芯片唯一序列号 0X34【指令代码：34H】( ====== 技术手册 ====== )
    uint8_t PS_GetChipSN[13] = {
        0XEF, 0X01,             // 包头
        0XFF, 0XFF, 0XFF, 0XFF, // 设备地址
        0X01,                   // 包标识
        0X00, 0X04,             // 包长度
        0X34,                   // 指令码
        0X00,                   // 参数
        0X00, 0X39              // 校验和
    };
    uart_write_bytes(UART_NUM_1, (const char *)PS_GetChipSN, 13);
    // 从 UART 接收数据，返回接收的字节数
    int len = uart_read_bytes(UART_NUM_1, data, (BUF_SIZE - 1), (100 / portTICK_PERIOD_MS));
    if (len)
    {
        // 判断 包标识是否为 0X07，以及确认码是否为 0X00。( ====== 技术手册 ====== )
        // 确认码: 00H 表示 OK；确认码: 01H 表示收包有错
        if (data[6] == 0X07 && data[9] == 0X00)
        {
            printf("获取指纹芯片的序列号: %.32s ......\r\n", &data[10]);
        }
        else if (data[6] == 0X07 && data[9] == 0X01)
        {
            printf("获取指纹芯片的序列号 Error, 收包错误......\r\n");
        }
    }
    free(data);
}

/**
 * @description: 获取指纹模板个数（也就是存了几个指纹）
 *               见技术手册: 3.3.1.16 读有效模板个数PS_ValidTempleteNum
 * @param {*} 无参
 * @return {*} 返回已经存储的指纹的数量
 */
uint8_t FINGERPRINT_GetTemplatesNumber(void)
{
    vTaskDelay(200 / portTICK_PERIOD_MS);
    uint8_t recvData[128] = {0};
    // 获取指纹模块中已经存储的指纹个数 0X1D【指令代码：1dH】( ====== 技术手册 ====== )
    uint8_t PS_ValidTempleteNum[12] = {
        0XEF, 0X01,             // 包头
        0XFF, 0XFF, 0XFF, 0XFF, // 设备地址
        0X01,                   // 包标识
        0X00, 0X03,             // 包长度
        0X1D,                   // 指令码
        0X00, 0X21              // 校验和
    };
    uart_write_bytes(UART_NUM_1, (const char *)PS_ValidTempleteNum, 12);
    // 从 UART 接收数据，返回接收的字节数
    int len = uart_read_bytes(UART_NUM_1, recvData, (BUF_SIZE - 1), (100 / portTICK_PERIOD_MS));
    if (len > 0)
    {
        // 判断 包标识是否为 0X07，以及确认码是否为 0X00。( ====== 技术手册 ====== )
        // 确认码: 00H 表示 OK；确认码: 01H 表示收包有错
        if (recvData[6] == 0X07 && recvData[9] == 0X00)
        {
            printf("指纹模块中已经存储的指纹个数: %d ......\r\n", recvData[11]);
            return recvData[11];
        }
        else if (recvData[6] == 0X07 && recvData[9] == 0X01)
        {
            printf("获取指纹模块中已经存储的指纹个数 Error, 收包错误......\r\n");
            return 0XFF;
        }
        return 0XFF;
    }
    return 0XFF;
}

/**
 * @description: 设置指纹模块进入休眠模式
 *               见技术手册: 3.3.1.19 休眠指令PS_Sleep
 * @param {*} 无参
 * @return {*} 返回 0 表示成功，返回 1 表示失败
 */
uint8_t FINGERPRINT_Sleep(void)
{
    vTaskDelay(200 / portTICK_PERIOD_MS);
    uint8_t recvData[128] = {0};
    // 设置指纹模块进入休眠模式 0X33【指令代码：33H】( ====== 技术手册 ====== )
    uint8_t PS_Sleep[12] = {
        0XEF, 0X01,             // 包头
        0XFF, 0XFF, 0XFF, 0XFF, // 设备地址
        0X01,                   // 包标识
        0X00, 0X03,             // 包长度
        0X33,                   // 指令码
        0X00, 0X37              // 校验和
    };
    uart_write_bytes(UART_NUM_1, (const char *)PS_Sleep, 12);
    // 从 UART 接收数据，返回接收的字节数
    int len = uart_read_bytes(UART_NUM_1, recvData, (BUF_SIZE - 1), (100 / portTICK_PERIOD_MS));
    if (len)
    {
        // 判断 包标识是否为 0X07，以及确认码是否为 0X00。( ====== 技术手册 ====== )
        // 确认码: 00H 表示 OK；确认码: 01H 表示收包有错
        if (recvData[6] == 0X07 && recvData[9] == 0X00)
        {
            printf("设置指纹模块进入休眠模式: 成功 ......\r\n");
            return 0;
        }
        else if (recvData[6] == 0X07 && recvData[9] == 0X01)
        {
            printf("设置指纹模块进入休眠模式: 失败, 收包错误 ......\r\n");
            return 1;
        }
        return 1;
    }
    return 1;
}

/**
 * @description: 设置取消自动注册模板和自动验证指纹
 *               见技术手册: 3.3.2.1 取消指令PS_Cancel
 * @param {*} 无参
 * @return {*} 无返回值
 */
void FINGERPRINT_Cancel(void)
{
    vTaskDelay(200 / portTICK_PERIOD_MS);
    uint8_t recvData[128] = {0};
    // 取消正在进行的录入指纹或者验证指纹流程，防止指纹模块假死
    // 设置取消自动注册模板和自动验证指纹 0X30【指令代码：30H】( ====== 技术手册 ====== )
    // 校验和是从包标识到校验和之间所有的字节之和，包含包标识，不包含校验和
    // 校验和 = 0X01 + 0X00 + 0X03 + 0X30
    // 快速计算：终端 ---> 输入python ---> 输入 0X01 + 0X00 + 0X03 + 0X30 得到结果 ---> hex(结果)
    uint8_t PS_Cancel[12] = {
        0XEF, 0X01,             // 包头
        0XFF, 0XFF, 0XFF, 0XFF, // 设备地址
        0X01,                   // 包标识
        0X00, 0X03,             // 包长度
        0X30,                   // 指令码
        0X00, 0X34              // 校验和
    };
    uart_write_bytes(UART_NUM_1, (const char *)PS_Cancel, 12);
    // 从 UART 接收数据，返回接收的字节数
    int len = uart_read_bytes(UART_NUM_1, recvData, (BUF_SIZE - 1), (100 / portTICK_PERIOD_MS));
    if (len)
    {
        // 判断 包标识是否为 0X07，以及确认码是否为 0X00。( ====== 技术手册 ====== )
        // 确认码: 00H 表示 OK；确认码: 01H 表示收包有错
        if (recvData[6] == 0X07 && recvData[9] == 0X00)
        {
            printf("设置取消自动注册模板和自动验证指纹: 成功 ......\r\n");
        }
        else if (recvData[6] == 0X07 && recvData[9] == 0X01)
        {
            printf("设置取消自动注册模板和自动验证指纹: 失败, 收包有错 ......\r\n");
        }
        else if (recvData[6] == 0X07 && recvData[9] == 0X31)
        {
            printf("设置取消自动注册模板和自动验证指纹: 失败, 功能与加密等级不匹配 ......\r\n");
        }
    }
}

/**
 * @description: 获取指纹图像
 *               见技术手册: 3.3.1.1 验证用获取图像PS_GetImage
 * @param {*} 无参
 * @return {*} 返回 0 表示成功，返回 1 表示失败
 */
uint8_t FINGERPRINT_GetImage(void)
{
    vTaskDelay(200 / portTICK_PERIOD_MS);
    uint8_t recvData[128] = {0};
    // 验证指纹时，探测手指，探测到后录入指纹图像存于图像缓冲区
    // 获取指纹图像 0X01【指令代码：01H】( ====== 技术手册 ====== )
    uint8_t PS_GetImage[12] = {
        0XEF, 0X01,             // 包头
        0XFF, 0XFF, 0XFF, 0XFF, // 设备地址
        0X01,                   // 包标识
        0X00, 0X03,             // 包长度
        0X01,                   // 指令码
        0X00, 0X05              // 校验和
    };
    uart_write_bytes(UART_NUM_1, (const char *)PS_GetImage, 12);
    // 从 UART 接收数据，返回接收的字节数
    int len = uart_read_bytes(UART_NUM_1, recvData, (BUF_SIZE - 1), (100 / portTICK_PERIOD_MS));
    if (len)
    {
        // 判断 包标识是否为 0X07，以及确认码是否为 0X00。( ====== 技术手册 ====== )
        // 确认码: 00H 表示 OK；确认码: 01H 表示收包有错
        if (recvData[6] == 0X07 && recvData[9] == 0X00)
        {
            printf("获取指纹图像: 成功 ......\r\n");
            return 0;
        }
        else if (recvData[6] == 0X07 && recvData[9] == 0X01)
        {
            printf("获取指纹图像: 失败, 收包有错 ......\r\n");
            return 1;
        }
        else if (recvData[6] == 0X07 && recvData[9] == 0X02)
        {
            printf("获取指纹图像: 失败, 传感器上无手指 ......\r\n");
            return 1;
        }
        return 1;
    }
    return 1;
}

/**
 * @description: 生成指纹特征
 *               见技术手册: 3.3.1.2 生成特征PS_GenChar
 * @param {uint8_t} BufferID 缓冲区号 ID。注：在注册过程中，BufferID 表示此次提取的特征存放在缓冲区中的位置；其他情况中，BufferID 有相应的默认值。
 * @return {*} 返回 0 表示成功，返回 1 表示失败
 */
uint8_t FINGERPRINT_GenerateCharacte(uint8_t BufferID)
{
    vTaskDelay(200 / portTICK_PERIOD_MS);
    uint8_t recvData[128] = {0};
    // 将图像缓冲区中的原始图像生成指纹特征文件存于模板缓冲区
    // 生成指纹特征 0X02【指令代码：02H】( ====== 技术手册 ====== )
    uint8_t PS_GenChar[13] = {
        0XEF, 0X01,             // 包头
        0XFF, 0XFF, 0XFF, 0XFF, // 设备地址
        0X01,                   // 包标识
        0X00, 0X04,             // 包长度
        0X02,                   // 指令码
        '\0',                   // 缓冲区号 ID
        '\0', '\0'              // 校验和（要进行计算）
    };
    PS_GenChar[10] = BufferID;
    // 计算校验和
    uint16_t sum = PS_GenChar[6] + PS_GenChar[7] + PS_GenChar[8] + PS_GenChar[9] + PS_GenChar[10];
    PS_GenChar[11] = (sum >> 8);
    PS_GenChar[12] = sum;
    uart_write_bytes(UART_NUM_1, (const char *)PS_GenChar, 13);
    // 从 UART 接收数据，返回接收的字节数
    int len = uart_read_bytes(UART_NUM_1, recvData, (BUF_SIZE - 1), (500 / portTICK_PERIOD_MS));
    if (len)
    {
        // 判断 包标识是否为 0X07，以及确认码是否为 0X00。( ====== 技术手册 ====== )
        // 确认码: 00H 表示 OK；确认码: 01H 表示收包有错
        if (recvData[6] == 0X07 && recvData[9] == 0X00)
        {
            printf("生成指纹特征: 成功 ......\r\n");
            return 0;
        }
        else if (recvData[6] == 0X07 && recvData[9] == 0X01)
        {
            printf("生成指纹特征: 失败, 收包有错 ......\r\n");
            return 1;
        }
        else if (recvData[6] == 0X07 && recvData[9] == 0X06)
        {
            printf("生成指纹特征: 失败, 指纹图像太乱而生不成特征 ......\r\n");
            return 1;
        }
        else if (recvData[6] == 0X07 && recvData[9] == 0X07)
        {
            printf("生成指纹特征: 失败, 指纹图像正常, 但特征点太少而生不成特征 ......\r\n");
            return 1;
        }
        else if (recvData[6] == 0X07 && recvData[9] == 0X08)
        {
            printf("生成指纹特征: 失败, 当前指纹特征与之前特征之间无关联 ......\r\n");
            return 1;
        }
        else if (recvData[6] == 0X07 && recvData[9] == 0X0A)
        {
            printf("生成指纹特征: 合并失败 ......\r\n");
            return 1;
        }
        else if (recvData[6] == 0X07 && recvData[9] == 0X15)
        {
            printf("生成指纹特征: 失败, 图像缓冲区内没有有效原始图而生不成图像 ......\r\n");
            return 1;
        }
        else if (recvData[6] == 0X07 && recvData[9] == 0X28)
        {
            printf("生成指纹特征: 失败, 当前指纹特征与之前特征之间有关联 ......\r\n");
            return 1;
        }
        return 1;
    }
    return 1;
}

/**
 * @description: 合并特征（生成模版 / 指纹）
 *               见技术手册: 3.3.1.5 合并特征（生成模板）PS_RegModel
 * @param {*} 无参
 * @return {*} 返回 0 表示成功，返回 1 表示失败
 */
uint8_t FINGERPRINT_RegModel(void)
{
    vTaskDelay(200 / portTICK_PERIOD_MS);
    uint8_t recvData[128] = {0};
    // 将特征文件融合后生成一个模板，结果存于模板缓冲区中
    // 合并特征（生成模板） 0X01【指令代码：01H】( ====== 技术手册 ====== )
    uint8_t PS_RegModel[12] = {
        0XEF, 0X01,             // 包头
        0XFF, 0XFF, 0XFF, 0XFF, // 设备地址
        0X01,                   // 包标识
        0X00, 0X03,             // 包长度
        0X05,                   // 指令码
        0X00, 0X09              // 校验和
    };
    // 通过串口发送数据
    uart_write_bytes(UART_NUM_1, (const char *)PS_RegModel, 12);
    // 从 UART 接收数据，返回接收的字节数
    int len = uart_read_bytes(UART_NUM_1, recvData, (BUF_SIZE - 1), (500 / portTICK_PERIOD_MS));
    if (len)
    {
        // 判断 包标识是否为 0X07，以及确认码是否为 0X00。( ====== 技术手册 ====== )
        // 确认码: 00H 表示 OK；确认码: 01H 表示收包有错
        if (recvData[6] == 0X07 && recvData[9] == 0X00)
        {
            printf("合并特征（生成模板）: 成功 ......\r\n");
            return 0;
        }
        else if (recvData[6] == 0X07 && recvData[9] == 0X01)
        {
            printf("合并特征（生成模板）: 失败, 收包有错 ......\r\n");
            return 1;
        }
        else if (recvData[6] == 0X07 && recvData[9] == 0X0A)
        {
            printf("合并特征（生成模板）: 失败, 合并失败 ......\r\n");
            return 1;
        }
        return 1;
    }
    return 1;
}

/**
 * @description: 储存模板(存储指纹)
 *               见技术手册: 3.3.1.6 储存模板PS_StoreChar
 * @param {uint8_t} PageID 指纹库位置号
 * @return {*} 返回 0 表示成功，返回 1 表示失败
 */
uint8_t FINGERPRINT_StoreChar(uint8_t PageID)
{
    vTaskDelay(200 / portTICK_PERIOD_MS);
    uint8_t recvData[128] = {0};
    // 将模板缓冲区中的模板文件存到 PageID 号 flash 数据库位置。如加密等级设置为 0 或 1 情况下支持此功能
    // 储存模板(存储指纹) 0X06【指令代码：06H】( ====== 技术手册 ====== )
    uint8_t PS_StoreChar[15] = {
        0XEF, 0X01,             // 包头
        0XFF, 0XFF, 0XFF, 0XFF, // 设备地址
        0X01,                   // 包标识
        0X00, 0X06,             // 包长度
        0X06,                   // 指令码
        '\0',                   // 缓冲区号 ID
        0X00, '\0',             // 页号, 指纹库位置号
        '\0', '\0'              // 校验和
    };
    PS_StoreChar[10] = 0X01;
    PS_StoreChar[12] = PageID;
    uint16_t sum = PS_StoreChar[6] + PS_StoreChar[7] + PS_StoreChar[8] + PS_StoreChar[9] + PS_StoreChar[10] + PS_StoreChar[11] + PS_StoreChar[12];
    PS_StoreChar[13] = (sum >> 8);
    PS_StoreChar[14] = sum;
    // 通过串口发送数据
    uart_write_bytes(UART_NUM_1, (const char *)PS_StoreChar, 15);
    // 从 UART 接收数据，返回接收的字节数
    int len = uart_read_bytes(UART_NUM_1, recvData, (BUF_SIZE - 1), (500 / portTICK_PERIOD_MS));
    if (len)
    {
        // 判断 包标识是否为 0X07，以及确认码是否为 0X00。( ====== 技术手册 ====== )
        // 确认码: 00H 表示 OK；确认码: 01H 表示收包有错
        if (recvData[6] == 0X07 && recvData[9] == 0X00)
        {
            printf("储存模板(存储指纹) : 成功 ......\r\n");
            return 0;
        }
        else if (recvData[6] == 0X07 && recvData[9] == 0X01)
        {
            printf("储存模板(存储指纹) : 失败, 收包有错 ......\r\n");
            return 1;
        }
        else if (recvData[6] == 0X07 && recvData[9] == 0X0B)
        {
            printf("储存模板(存储指纹) : 失败, PageID 超出指纹库范围 ......\r\n");
            return 1;
        }
        else if (recvData[6] == 0X07 && recvData[9] == 0X18)
        {
            printf("储存模板(存储指纹) : 失败, 写 FLASH 出错 ......\r\n");
            return 1;
        }
        else if (recvData[6] == 0X07 && recvData[9] == 0X31)
        {
            printf("储存模板(存储指纹) : 失败, 功能与加密等级不匹配 ......\r\n");
            return 1;
        }
        return 1;
    }
    return 1;
}

/**
 * @description: 设置安全等级为 0
 *               见技术手册: 3.3.1.12 写系统寄存器PS_WriteReg
 * @param {*} 无参
 * @return {*} 返回 0 表示成功，返回 1 表示失败
 */
uint8_t FINGERPRINT_SetSecurityLevelAsZero(void)
{
    vTaskDelay(200 / portTICK_PERIOD_MS);
    uint8_t recvData[128] = {0};
    // 写模组寄存器
    // 设置安全等级为0, 0X0E【指令代码：0EH】( ====== 技术手册 ====== )
    uint8_t PS_WriteReg[14] = {
        0XEF, 0X01,             // 包头
        0XFF, 0XFF, 0XFF, 0XFF, // 设备地址
        0X01,                   // 包标识
        0X00, 0X05,             // 包长度
        0X0E,                   // 指令码
        '\0',                   // 寄存器序号
        '\0',                   // 要写入的内容
        '\0', '\0'              // 校验和
    };
    // 寄存器号为: 7, 表示该寄存器是 加密等级寄存器
    PS_WriteReg[10] = 0X07;
    // 等级为 0
    PS_WriteReg[11] = 0X00;
    uint16_t sum = PS_WriteReg[6] + PS_WriteReg[7] + PS_WriteReg[8] + PS_WriteReg[9] + PS_WriteReg[10] + PS_WriteReg[11];
    PS_WriteReg[12] = (sum >> 8);
    PS_WriteReg[13] = sum;
    // 通过串口发送数据
    uart_write_bytes(UART_NUM_1, (const char *)PS_WriteReg, 15);
    // 从 UART 接收数据，返回接收的字节数
    int len = uart_read_bytes(UART_NUM_1, recvData, (BUF_SIZE - 1), (100 / portTICK_PERIOD_MS));
    if (len)
    {
        // 判断 包标识是否为 0X07，以及确认码是否为 0X00。( ====== 技术手册 ====== )
        // 确认码: 00H 表示 OK；确认码: 01H 表示收包有错
        if (recvData[6] == 0X07 && recvData[9] == 0X00)
        {
            printf("设置安全等级: 成功 ......\r\n");
            return 0;
        }
        else if (recvData[6] == 0X07 && recvData[9] == 0X01)
        {
            printf("设置安全等级: 失败, 收包有错 ......\r\n");
            return 1;
        }
        else if (recvData[6] == 0X07 && recvData[9] == 0X18)
        {
            printf("设置安全等级 : 失败, 读写 FLASH 出错 ......\r\n");
            return 1;
        }
        else if (recvData[6] == 0X07 && recvData[9] == 0X1A)
        {
            printf("设置安全等级 : 失败, 寄存器序号有误 ......\r\n");
            return 1;
        }
        else if (recvData[6] == 0X07 && recvData[9] == 0X1B)
        {
            printf("设置安全等级 : 失败, 寄存器设定内容错误号 ......\r\n");
            return 1;
        }
        return 1;
    }
    return 1;
}

/**
 * @description: 注册指纹流程
 *               见技术手册: 4.2.1 通用指令注册指纹流程
 * @param {uint8_t} PageID 指纹库位置号
 * @return {*} 返回 0 表示成功，返回 1 表示失败
 */
uint8_t FINGERPRINT_Enroll(uint8_t PageID)
{
    uint8_t n = 1;
SendGetImageLabel:
    if (FINGERPRINT_GetImage())
        goto SendGetImageLabel;
    if (FINGERPRINT_GenerateCharacte(n))
        goto SendGetImageLabel;
    printf("第 %d 次获取图像以及生成特征成功 ......\r\n", n);
    // 请拿开手指
    AUDIO_Play(82);
    DelayMs(2000);
    if (n < 4)
    {
        // 请再次放置手指
        AUDIO_Play(81);
        DelayMs(1000);
        n += 1;
        goto SendGetImageLabel;
    }
    if (FINGERPRINT_RegModel())
        goto ERROR;
    if (FINGERPRINT_StoreChar(PageID))
        goto ERROR;
    // 指纹添加成功
    AUDIO_Play(83);
    return 0;
ERROR:
    // 指纹添加失败
    AUDIO_Play(84);
    return 1;
}

/**
 * @description: 搜索指纹
 *               见技术手册: 3.3.1.4 搜索指纹PS_Search
 * @param {*} 无参
 * @return {*} 返回 0 表示成功，返回 1 表示失败
 */
uint8_t FINGERPRINT_SearchFinger(void)
{
    vTaskDelay(200 / portTICK_PERIOD_MS);
    uint8_t recvData[128] = {0};
    // 以模板缓冲区中的特征文件搜索整个或部分指纹库。若搜索到，则返回页码。如加密等级设置为 0 或 1 情况下支持此功能。
    // 搜索指纹, 0X04【指令代码：04H】( ====== 技术手册 ====== )
    uint8_t PS_Search[17] = {
        0XEF, 0X01,             // 包头
        0XFF, 0XFF, 0XFF, 0XFF, // 设备地址
        0X01,                   // 包标识
        0X00, 0X08,             // 包长度
        0X04,                   // 指令码
        '\0',                   // 缓冲区号 ID
        '\0', '\0',             // StartPage（起始页）
        '\0', '\0',             // PageNum（页数）
        '\0', '\0'              // 校验和
    };
    // 注：BufferID 默认为 1，以模板缓冲区中指纹模板搜索整个或部分指纹库。
    PS_Search[10] = 0X01;
    // StartPage（起始页）
    PS_Search[11] = 0X00;
    PS_Search[12] = 0X00;
    // PageNum（页数）
    PS_Search[13] = 0XFF;
    PS_Search[14] = 0XFF;
    // 校验和
    uint16_t sum = PS_Search[6] + PS_Search[7] + PS_Search[8] + PS_Search[9] + PS_Search[10] + PS_Search[11] + PS_Search[12] + PS_Search[13] + PS_Search[14];
    PS_Search[15] = (sum >> 8);
    PS_Search[16] = sum;
    // 通过串口发送数据
    uart_write_bytes(UART_NUM_1, (const char *)PS_Search, 17);
    // 从 UART 接收数据，返回接收的字节数
    int len = uart_read_bytes(UART_NUM_1, recvData, (BUF_SIZE - 1), (500 / portTICK_PERIOD_MS));
    if (len)
    {
        // 判断 包标识是否为 0X07，以及确认码是否为 0X00。( ====== 技术手册 ====== )
        // 确认码: 00H 表示 OK；确认码: 01H 表示收包有错
        if (recvData[6] == 0X07 && recvData[9] == 0X00)
        {
            printf("搜索指纹: 成功 ......\r\n");
            return 0;
        }
        else if (recvData[6] == 0X07 && recvData[9] == 0X01)
        {
            printf("搜索指纹: 失败, 收包有错 ......\r\n");
            return 1;
        }
        else if (recvData[6] == 0X07 && recvData[9] == 0X09)
        {
            printf("搜索指纹 : 失败, 没搜索到; 此时页码与得分为 0 ......\r\n");
            return 1;
        }
        else if (recvData[6] == 0X07 && recvData[9] == 0X17)
        {
            printf("搜索指纹 : 失败, 残留指纹或两次采集之间手指没有移动过 ......\r\n");
            return 1;
        }
        else if (recvData[6] == 0X07 && recvData[9] == 0X31)
        {
            printf("搜索指纹 : 失败, 功能与加密等级不匹配 ......\r\n");
            return 1;
        }
        return 1;
    }
    return 1;
}

/**
 * @description: 验证指纹流程
 *               见技术手册: 4.2.2 通用指令验证指纹流程
 * @param {*} 无参
 * @return {*} 返回 0 表示成功，返回 1 表示失败
 */
uint8_t FINGERPRINT_Identify(void)
{
    if (FINGERPRINT_GetImage())
        return 1;
    // BufferID 设为默认值为 1
    if (FINGERPRINT_GenerateCharacte(1))
        return 1;
    if (FINGERPRINT_SearchFinger())
        return 1;
    return 0;
}
